package com.vaye.common.utils;

import cn.dev33.satoken.secure.SaSecureUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.digest.MD5;
import com.google.common.base.Charsets;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.vaye.common.constant.ImConstant;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.mindrot.jbcrypt.BCrypt;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.MessageDigest;
import java.security.SecureRandom;

/**
 * 加密算法工具类
 *
 * @author wangzhiyong
 * @module admin
 * @date 2023年05月31日 下午5:13
 */
@Slf4j
public class DigestUtil {

    /**
     * AES加密密码，写死
     */
    private static final String password = "87dc714e1f4c41a2ad3e6a2b30fef32d";

    /**
     * 密码加密
     * @author wangzhiyong
     * @date 2023/5/31 下午5:14
     * @param password
     * @return java.lang.String
     */
    public static String encryptPassword(String password) {
        int workload = 12;
        String salt = BCrypt.gensalt(workload);
        return BCrypt.hashpw(password, salt);
    }

    /**
     * 密码校验
     * @author wangzhiyong
     * @date 2023/6/1 上午9:46
     * @param password 明文密码
     * @param hashed 加密后的密码串
     * @return boolean
     */
    public static boolean checkPassword(String password,String hashed) {
        return BCrypt.checkpw(password,hashed);
    }

    public static String encodeSHA512(String source, String salt) {
        try {
            if (StringUtils.isEmpty(source)) {
                return null;
            } else {
                byte[] saltByte = salt == null ? null : salt.getBytes("UTF-8");
                byte[] sourceByte = source.getBytes("UTF-8");
                MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
                if (saltByte == null) {
                    return encodeHex(messageDigest.digest(sourceByte));
                } else {
                    messageDigest.update(saltByte);
                    return encodeHex(messageDigest.digest(sourceByte));
                }
            }
        } catch (Exception var5) {
            throw new IllegalStateException(var5.getMessage(), var5);
        }
    }

    public static String encodeHex(byte[] bytes) {
        StringBuffer buffer = new StringBuffer(bytes.length * 2);
        for(int i = 0; i < bytes.length; ++i) {
            if ((bytes[i] & 255) < 16) {
                buffer.append("0");
            }
            buffer.append(Long.toString((long)(bytes[i] & 255), 16));
        }
        return buffer.toString();
    }

    /**
     * 生成加密盐值
     * @author wangzhiyong
     * @date 2023/6/1 上午10:02
     * @return java.lang.String
     */
    public static String generateSalt() {
        SecureRandom secureRandom = new SecureRandom();
        byte[] saltBytes = new byte[16];
        secureRandom.nextBytes(saltBytes);
        return Base64.encodeBase64String(saltBytes);
    }

    /**
     * MD5加密
     *
     * @param source
     * @return
     */
    public static String MD5(String source) {
        Hasher hasher = Hashing.md5().newHasher();
        hasher.putString(source, Charsets.UTF_8);
        return hasher.hash().toString().toUpperCase();
    }

    /**
     * 两重加密，针对前端登录密码加密
     *
     * @param source
     * @return
     */
    public static String encryptPassword2(String source) {
        String second = MD5(source);
        Hasher sha256 = Hashing.sha256().newHasher();
        sha256.putString(second, Charsets.UTF_8);
        return sha256.hash().toString().toUpperCase();
    }

    /**
     * 生成token，这个token是userId和userName的AES加密信息，将作为缓存的key，登录cookie的value
     * 为什么是AES加密？因为部分业务需要将这个值取出来后解密拿出其中的userName
     * @author wangzhiyong
     * @date 2023/6/1 上午10:09
     * @param userId 用户ID
     * @param userName 用户名
     * @param nickName 用户昵称
     * @return java.lang.String
     */
    public static String token(Long userId, String userName,String nickName) throws Exception {
        String timestamp = String.valueOf(System.currentTimeMillis());
        return encodeAES(String.format(ImConstant.TOKEN_FORMAT,userId,userName,nickName,timestamp));
    }

    public static String token(Long userId, String userName) throws Exception {
        return encodeAES(userId + "_" + userName);
    }

    /**
     * 解密token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public static String[] decodeToken(String token) throws Exception {
        return decodeAES(token).split(ImConstant.SEPARATE_TOKEN);
    }

    /**
     * AES加密
     *
     * @param source
     * @return
     * @throws Exception
     */
    public static String encodeAES(String source) throws Exception {
        // 生成key
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(password.getBytes());
        keyGenerator.init(128, secureRandom);//new SecureRandom(password.getBytes())
        SecretKey secretKey = keyGenerator.generateKey();
        byte[] keyBytes = secretKey.getEncoded();
        // key转换
        Key key = new SecretKeySpec(keyBytes, "AES");
        // 加密
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] result = cipher.doFinal(source.getBytes());
        String res = Base64.encodeBase64String(result);
        log.info("jdkAES encrypt:" + res);
        return res;
    }

    /**
     * AES解密
     *
     * @param target
     * @return
     * @throws Exception
     */
    public static String decodeAES(String target) throws Exception {
        // 生成key
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(password.getBytes());
        keyGenerator.init(128, secureRandom);//new SecureRandom(password.getBytes())
        SecretKey secretKey = keyGenerator.generateKey();
        byte[] keyBytes = secretKey.getEncoded();
        // key转换
        Key key = new SecretKeySpec(keyBytes, "AES");
        // 解密
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] result_decrypt = cipher.doFinal(Base64.decodeBase64(target));
        String result = new String(result_decrypt);
        log.info("jdkAES decrypt:" + result);
        return result;
    }

    public static void main(String[] args) throws Exception {
        String s = String.valueOf(System.currentTimeMillis());
        String token = token(1L, "test_c");
        System.out.println("token = " + token);
        String password = encodeSHA512(UuidUtils.getUUIDStr(),s);
        System.out.println("s2 = " + password);
        String salt = RandomUtil.randomString(6);
        String s1 = MD5.create().digestHex16("123456" + salt, StandardCharsets.UTF_8);
        System.out.println("s1 = " + s1);
        String s2 = SaSecureUtil.md5BySalt("123456", salt);
        System.out.println("s2 = " + s2);
    }
}
